package com.zw.cloud.tools.controller.wechat;

import cn.hutool.json.XML;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import com.thoughtworks.xstream.XStream;
import com.zw.cloud.common.utils.DingTalkUtils;
import com.zw.cloud.common.utils.weixin.WeChatAesUtils;
import com.zw.cloud.global.response.wrapper.annotation.NotNeedResponseAutoWrapper;
import com.zw.cloud.tools.entity.wechat.WeChatMenu;
import com.zw.cloud.tools.entity.wechat.WeChatMenuButtonDTO;
import com.zw.cloud.tools.entity.wechat.WeChatReceiveMsg;
import com.zw.cloud.tools.entity.wechat.WeChatResponseMsg;
import com.zw.cloud.tools.service.AliyunTalkService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 微信公众号介入(校验签名)
 * https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html
 * https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index
 * 测试平台
 * https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index
 */
@RestController
@RequestMapping(value = "/weChat")
@Slf4j
public class WeChatController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    WxMpService wxMpService;

    @Autowired
    private AliyunTalkService aliyunTalkService;

    private static final String appid = "wx38237281a69df8d4";

    private static final String secret = "779c68851baaeb2af117efd874f1ca08";

    @GetMapping(value = "/check",produces = "text/plain;charset=utf-8")
    @NotNeedResponseAutoWrapper
    public String wxCheck(@RequestParam(name = "signature", required = false) String signature,
                        @RequestParam(name = "timestamp", required = false) String timestamp,
                        @RequestParam(name = "nonce", required = false) String nonce,
                        @RequestParam(name = "echostr", required = false) String echostr){
        String checkSignature = creatSHA1("zhengwei",timestamp,nonce);
        if (checkSignature.equals(signature)){
            log.info("[WeChatController][wxCheck]success");
            return echostr;
        }
        return null;
    }

    @GetMapping("/getAccessToken")
    @NotNeedResponseAutoWrapper
    //http://localhost:9040/weChat/getAccessToken
    public JSONObject getAccessToken() {
        HashMap<String, String> paramMap = new HashMap<>();
        paramMap.put("grant_type","client_credential");
        paramMap.put("appid",appid);
        paramMap.put("secret",secret);
        return restTemplate.postForObject("https://api.weixin.qq.com/cgi-bin/stable_token",paramMap, JSONObject.class);
    }

    /*@GetMapping("/getAccessToken")
    @NotNeedResponseAutoWrapper
    //http://localhost:9040/weChat/getAccessToken
    public JSONObject sendWxMsg() {

        //2,推送消息
        WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
                .toUser(commonConfig.getTouser())
                .templateId(commonConfig.getTemplateId())
                .build();
        //3,如果是正式版发送模版消息，这里需要配置你的信息
        templateMessage.addData(new WxMpTemplateData("riqi",forecastsVO.getDate() + "  "+ forecastsVO.getWeek(),"#00BFFF"));
        templateMessage.addData(new WxMpTemplateData("tiani",forecastsVO.getText_day(),"#00FFFF"));
        templateMessage.addData(new WxMpTemplateData("low",forecastsVO.getLow() + "","#173177"));
        templateMessage.addData(new WxMpTemplateData("high",forecastsVO.getHigh()+ "","#FF6347" ));
        templateMessage.addData(new WxMpTemplateData("caihongpi",caiHongPiInfoResult.getContent(),"#FF69B4"));
        // 恋爱时间、生日可自行计算(so easy)
        templateMessage.addData(new WxMpTemplateData("lianai","-365","#FF1493"));
        templateMessage.addData(new WxMpTemplateData("shengri","120","#FFA500"));
        String beizhu = "宝贝";
        templateMessage.addData(new WxMpTemplateData("beizhu",beizhu,"#FF0000"));
        System.out.println(templateMessage.toJson());
        System.out.println(wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage));

    }*/

    /**
     * 自定义菜单 /创建接口
     */
    @GetMapping("/createMenu")
    @NotNeedResponseAutoWrapper
    //http://localhost:9040/weChat/createMenu?accessToken=72_zS2aWFGPIY0yCTzAgl7GIVyqYkx6fgONbdaVSBmxb-AY7ENVd7UgIQ0_WBW0EyTkquzru_ahnjI3-hywQ4ealHr8TTChP0pb_KiEa0wcKCg9Q5_LKCftOpdlGvcWYZeAAADFG
    public JSONObject createMenu(@RequestParam(required = false) String accessToken) {
        if (StringUtils.isBlank(accessToken)) {
            JSONObject accessTokenRes = getAccessToken();
            log.info("[WeChatController][createMenu]accessTokenRes is {}", JSON.toJSONString(accessTokenRes));
            accessToken = String.valueOf(accessTokenRes.get("access_token"));
        }

        WeChatMenuButtonDTO wChatMenuButtonDTO =  new WeChatMenuButtonDTO();
        List<WeChatMenu> buttonList = new ArrayList<>();
        WeChatMenu webMenuClick = new WeChatMenu();
        webMenuClick.setType("click");
        webMenuClick.setKey("V1001_TODAY");
        webMenuClick.setName("每日一句");
        buttonList.add(webMenuClick);

        // 菜单-常用工具
        WeChatMenu subButton1 = new WeChatMenu();
        subButton1.setType("view");
        subButton1.setName("常用工具");
        subButton1.setUrl("http://123.60.169.183:9040/app");

        // 菜单-扫码
        WeChatMenu subButton2 = new WeChatMenu();
        subButton2.setType("scancode_push");
        subButton2.setName("扫码推事件");
        subButton2.setKey("scan1");

        WeChatMenu menu = new WeChatMenu();
        menu.setSub_button(Lists.newArrayList(subButton1,subButton2));
        menu.setName("菜单");
        buttonList.add(menu);

        wChatMenuButtonDTO.setButton(buttonList);
        log.info("[WeChatController][createMenu]accessToken is {},wChatMenuButtonDTO is {}", accessToken,JSON.toJSONString(wChatMenuButtonDTO));
        return restTemplate.postForObject("https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + accessToken,wChatMenuButtonDTO,JSONObject.class);
    }

    /**
     * 微信公众号交互
     * https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=1793775887&lang=zh_CN
     * 如果启用 公众号消息和机器人回复的消息会被接收
     */
    @PostMapping(value = "/check")
    @NotNeedResponseAutoWrapper
    public String receiveAndRespMsg(HttpServletRequest request) throws Exception {
        String msgSignature = request.getParameter("msg_signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        // postdata 即为 POST 过来的数据包内容
        String encryptMsg = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
        log.info("[WeChatController][receiveAndRespMsg]msgSignature is {},timestamp is {},nonce is {},encryptMsg is {}",
                msgSignature,timestamp,nonce,encryptMsg);
        // 消息解密
        String msg = WeChatAesUtils.decryptMsg(msgSignature, timestamp, nonce, encryptMsg);
        cn.hutool.json.JSONObject receiveMap = XML.toJSONObject(msg);
        WeChatReceiveMsg weChatReceiveMsg = JSON.parseObject(String.valueOf(receiveMap.get("xml")), WeChatReceiveMsg.class);
        //Map<String, String> receiveMap = parseXml(request);
        log.info("[WeChatController][receiveAndRespMsg]weChatReceiveMsg is {}", receiveMap.get("xml"));
        WeChatResponseMsg responseMsg = new WeChatResponseMsg(weChatReceiveMsg.getFromUserName(),weChatReceiveMsg.getToUserName());
        responseMsg.setMsgType("text");
        if (Objects.nonNull(weChatReceiveMsg.getCreateTime())) {
            responseMsg.setCreateTime(weChatReceiveMsg.getCreateTime());
        }
        // java 对象转为 XML
        XStream stream = new XStream();
        //注解使用
        stream.processAnnotations(WeChatResponseMsg.class);
        String msgType = weChatReceiveMsg.getMsgType();
        String content = weChatReceiveMsg.getContent();
        switch (msgType) {
            case "event":
                String event = weChatReceiveMsg.getEvent();
                if ("subscribe".equalsIgnoreCase(event)) {
                    responseMsg.setContent("你好，欢迎您的加入! \n 常用工具 \n http://123.60.169.183:9040/app \n 开始和AI对话吧...");
                } else if ("CLICK".equalsIgnoreCase(event)) {
                    // 点击菜单拉取消息时的事件推送
                    JSONObject result = restTemplate.getForObject("https://v1.hitokoto.cn", JSONObject.class);
                    responseMsg.setContent(String.valueOf(result.get("hitokoto")));
                } else if ("VIEW".equalsIgnoreCase(event)) {
                    // 点击菜单跳转链接时的事件推送
                    responseMsg.setContent("感谢您的浏览!");
                } else if ("scancode_push".equalsIgnoreCase(event) && "scan1".equalsIgnoreCase(weChatReceiveMsg.getEventKey())) {
                    // scancode_push：扫码推事件的事件推送
                    responseMsg.setContent("扫码结果为: \n " + receiveMap.get("ScanResult"));
                }
                break;
            case "text":
                responseMsg.setContent(handleTextMsg(weChatReceiveMsg.getFromUserName(),content));
                break;
            case "image":
                // https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Getting_Started_Guide.html#_5-2-%E8%8E%B7%E5%8F%96%E4%B8%B4%E6%97%B6%E7%B4%A0%E6%9D%90MediaID
                responseMsg.setContent("感谢您的图片!");
                break;
            case "voice":
                responseMsg.setContent("感谢您的语言消息!");
                break;
            case "video":
                responseMsg.setContent("感谢您的视频!");
                break;
            case "shortvideo":
                responseMsg.setContent("感谢您的短视频!");
                break;
            case "location":
                responseMsg.setContent("感谢您的位置信息!");
                break;
            case "link":
                responseMsg.setContent("感谢您分享的链接!");
                break;
            default:
                return "success";
        }
        String xml = stream.toXML(responseMsg);
        // 消息加密
        String encryptedMsg = WeChatAesUtils.encryptMsg(xml, String.valueOf(responseMsg.getCreateTime()), UUID.randomUUID().toString());
        log.info("[WeChatController][receiveAndRespMsg]encryptedMsg is {}", encryptedMsg);
        return encryptedMsg;
    }

    private String handleTextMsg(String userId,String content) {
        try {
            return aliyunTalkService.talk(userId, content);
        } catch (Exception e) {
            return "服务异常,稍后重试";
        }
        /*if (content.startsWith("钉钉消息")) {
            DingTalkUtils.sendDingTalkMsgWithSign("微信消息",content);
            return "钉钉消息已发送";
        } else {
            JSONObject result = restTemplate.getForObject("https://v1.hitokoto.cn", JSONObject.class);
            return content + " \n " + result.get("hitokoto");
        }*/
    }

    private String creatSHA1(String token, String timestamp, String nonce) {
        try {
            String[] array = new String[] { token, timestamp, nonce};
            StringBuffer sb = new StringBuffer();
            // 字符串排序
            Arrays.sort(array);
            for (int i = 0; i < 3; i++) {
                sb.append(array[i]);
            }
            String str = sb.toString();
            // SHA1签名生成
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            md.update(str.getBytes());
            byte[] digest = md.digest();

            StringBuffer hexstr = new StringBuffer();
            String shaHex = "";
            for (int i = 0; i < digest.length; i++) {
                shaHex = Integer.toHexString(digest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexstr.append(0);
                }
                hexstr.append(shaHex);
            }
            return hexstr.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

    private Map<String, String> parseXml(HttpServletRequest request) throws Exception {
        // 将解析结果存储在HashMap中
        Map<String, String> map = new HashMap<String, String>();

        // 从request中取得输入流
        InputStream inputStream = request.getInputStream();
        // 读取输入流
        SAXReader reader = new SAXReader();
        Document document = reader.read(inputStream);
        // 得到xml根元素
        Element root = document.getRootElement();
        // 得到根元素的所有子节点
        List<Element> elementList = root.elements();

        // 遍历所有子节点
        for (Element e : elementList)
            map.put(e.getName(), e.getText());

        // 释放资源
        inputStream.close();
        inputStream = null;

        return map;
    }
}
